JBoss Community Archive (Read Only)

GateIn Portal 3.9

Native AMD Modules

This feature is experimental.

The support for native AMD modules was added in GateIn Portal 3.8. Native AMD modules exhibit three main differences against GateIn Modules (GMD):

Motivation

Despite the great flexibility of GateIn Modules (GMD), there are a few situations where they cannot provide an appropriate solution. One such is a requirement to use a large 3rd party JavaScript framework such as Dojo. Dojo complies with the AMD specification and therefore it should in theory be possible to declare its modules as GMD Modules, but there is a couple of reasons why that is not a way to go:

  1. Large. Dojo 1.9.2 contains as many as 4899 JavaScript files. Can you imagine that you declare them in gatein-resources.xml? Well, it is perhaps possible, if you write a tool that does that for you. But such a tool would have to provide also the dependency tree which is by no means trivial.

  2. Extreme AMD. Although still AMD compliant, there are constructs, that GMD cannot handle at all:

    1. Relative module names. Let us have a dependeny graph as simple as: dojo/sniff depends on dojo/has. Given that both dojo/sniff and dojo/has live in the same directory named dojo, the dojo/sniff.js file can start with define(["./has"], function(has){ , but relative module path names like "./has" will not be handled by GMD.

    2. Cyclic dependencies. However questionable their purpose, this happens in the AMD world but GateIn Portal capitulates with an error when seeing them.

    3. Inline require. Calls like the following are legal in AMD but cannot be declared in any way in means of GMD: require([id == 'platform' ? platformId : defId], function(provider){...});. There are two problems with that: first, you do not know at development time what (and at which position) should be declared as a dependency in gatein-resources.xml and second, the GMD implementation does server-side wrapping of all modules which causes that these inline require() calls result in a request for a non-existent resource.

    4. Loader Plugins. Some specific loader plugins are supported in GateIn Portal (see GMD Module Resources), but their diversity in the AMD world is much broader than GMD is able to cover. In AMD, the string following the ! separator (i.e. the resource ID) is to be interpreted by the loader plugin, so effectively, they can mean just anything: be it an URL, name of another module, some magic string... But the present GMD implementation is able to interpret them as resource paths only.

Local Native AMD Modules

To solve all the above, the native AMD modules were introduced. Let us look how to use their local variant first.

This section cites code from an unofficial and experimental Dojo Portlet Quickstart hosted on GitHub: https://github.com/ppalaga/dojo-portlet/commits/master

To ease the declaration of AMD modules in gatein-resources.xml esp. in situations when there are lots of modules, the <amd> element was introduced. It offers Maven assembly-plugin like <includes> and <excludes> subelements so that a large amount of resources can be declared in a concise way.

gatein-resources.xml
<gatein-resources xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_resources_1_4 http://www.gatein.org/xml/ns/gatein_resources_1_4"
    xmlns="http://www.gatein.org/xml/ns/gatein_resources_1_4">

    <amd>
        <fileset>
            <directory>/dojo-release-1.9.2-src</directory>
            <excludes>
                <exclude>**/tests/**</exclude>
                <exclude>**/test/**</exclude>
                <exclude>**/.*/**</exclude>
                <exclude>**/*.php</exclude>
                <exclude>**/.*</exclude>
                <exclude>**/README</exclude>
                <exclude>**/LICENSE</exclude>
            </excludes>
        </fileset>
    </amd>

The above example includes everything important from an unchanged dojo source distribution present in src/main/webapp/dojo-release-1.9.2-src directory of the project. The path configured in <directory> element has to be relative to the root directory of your WAR. Declaring external paths such as http://mycdn.example.com/js/ is not supported in <directory>.

Both JavaScript files and non-JavaScript resources distributed with Dojo, such as images, HTML templates, CSS files, etc. are bulk-registered here. Note that the implicit and unchangeable scope of all resources imported in this way is SHARED.

Further, there is <native-amd> element which just marks a GMD style module as "being native AMD" to the effect that

  • Its source will not get wrapped in any way by GateIn Portal and

  • Its dependencies do not need to be declared explictly in gatein-resources.xml

gatein-resources.xml cont.
    <module>
        <name>dojoPortlet</name>
        <native-amd>true</native-amd>
        <script>
            <path>/js/dojo-portlet.js</path>
        </script>
    </module>

    <module>
        <name>dojoPortletWithButton</name>
        <native-amd>true</native-amd>
        <script>
            <path>/js/dojo-portlet-with-button.js</path>
        </script>
    </module>

In /js/dojo-portlet.js and /js/dojo-portlet-with-button.js we use modules from Dojo as dependencies in the usual AMD way:

/js/dojo-portlet.js
require(['dojo/fx', 'dojo/_base/fx', 'dojo/domReady!'], function (fx, coreFx) {
    fx.chain([
                  coreFx.fadeIn({ node: "dojoWorks", duration: 3000 }),
                  coreFx.fadeIn({ node: "inJBossPortal", duration: 3000 })
              ]).play();
});
/js/dojo-portlet-with-button.js
require(['dijit/form/Button','dojo/dom','dojo/domReady!'], function (Button, dom) {
    var myButton = new Button({
        label: "Click me!",
        onClick: function(){
            // Do something:
            dom.byId("dojoButtonResult").innerHTML += "Thank you! ";
        }
    }, "dojoButton");
});

/js/dojo-portlet.js and /js/dojo-portlet-with-button.js are then linked with the respective portlets in the final part of gatein-resources.xml

gatein-resources.xml final
    <portlet>
        <name>DojoPortlet</name>
        <module>
            <depends>
                <module>dojoPortlet</module>
            </depends>
        </module>
    </portlet>

    <portlet>
        <name>DojoPortletWithButton</name>
        <module>
            <depends>
                <module>dojoPortletWithButton</module>
            </depends>
        </module>
    </portlet>
</gatein-resources>

Native AMD Modules hosted on CDN

Since GateIn Portal 3.9, it is possible to use AMD modules hosted outside of the portal, e.g. on a Content Delivery Network (CDN).

This section cites code from an unofficial and experimental ArcGis Gears Portlet hosted on GitHub: https://github.com/ppalaga/arcgis-gears-portlet/commits/master

This feature is internally implemented using require.js path mappings which allow to map a module ID prefix to an URL to be used instead of the prefix.

The mappings entries need to be declared in the <amd> section of the gatein-resources.xml file:

gatein-resources.xml
<gatein-resources xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_resources_1_5 http://www.gatein.org/xml/ns/gatein_resources_1_5"
    xmlns="http://www.gatein.org/xml/ns/gatein_resources_1_5">

    <amd>
        <path-entry>
            <prefix>dojo</prefix><target-path>//js.arcgis.com/3.9/js/dojo/dojo</target-path>
        </path-entry>
        <path-entry>
            <prefix>dijit</prefix><target-path>//js.arcgis.com/3.9/js/dojo/dijit</target-path>
        </path-entry>
        <path-entry>
            <prefix>dojox</prefix><target-path>//js.arcgis.com/3.9/js/dojo/dojox</target-path>
        </path-entry>
        <path-entry>
            <prefix>esri</prefix><target-path>//js.arcgis.com/3.9/js/esri</target-path>
        </path-entry>
    </amd>

It is possible to assign multiple target paths to a given prefix which are then interpreted as fallback paths. E.g. you may want to put a third party CDN URL as the first choice there, but add a URL on your own server as a fallback URL:

Fallback paths
...
    <amd>
        <path-entry>
            <prefix>dojo</prefix>
            <target-path>//js.arcgis.com/3.9/js/dojo/dojo</target-path>
            <target-path>//mycompany.com/frameworks/dojo/1.9.1</target-path>
        </path-entry>
        ...
    </amd>
...

You can also use CSS hosted on a CDN. Please refer to Skinning the portal chapter of the Reference Guide.

Portal Wide Consistency of Path Mappings

There is only one global path mappings collection per Portal instance. Hence, when deploying a portlet application, the Portal can accept only such path mappings which are consistent with those ones that were declared earlier by other applications.

Let us look at an example:

  • Application app2 wants to register the AMD module ID prefix
    /dojo to be mapped to target path http://fastcdn.com/dojo/1.7.0

  • The prefix /dojo was previously registered by some other application app1 to point to a different target path http://othercdn.com/dojo/1.9.1.

  • Because adding the prefix /dojo to the available prefixes could break app1, no JavaScript or CSS resources from app2 will be accepted by the portal.

But as shown in the following example, adding the very same mapping multiple times is possible:

  • Application app2 wants to register the AMD module ID prefix
    /dojo to be mapped to target path http://fastcdn.com/dojo/1.7.0

  • The prefix /dojo was previously registered by some other application app1 to point to the very same target path http://fastcdn.com/dojo/1.7.0.

  • The path mapping from app2.war is accepted by the portal because it does not introduce any inconsistency.

JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-10 13:30:50 UTC, last content change 2014-06-25 15:25:53 UTC.